package com.heima.wemedia.service.impl;
/*
    
 需求描述：
 @Author: wang
 @Date: 2022/10/17 16:22
 
 */

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.exception.CustomException;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.builder.ArticleDtoBuilder;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutomaticCheckService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class WmNewsAutomaticCheckServiceImpl implements WmNewsAutomaticCheckService {

    @Autowired
    private WmNewsMapper newsMapper;

    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan greenImageScan;
    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private IArticleClient articleClient;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmSensitiveMapper sensitiveMapper;

    @Autowired
    private Tess4jClient tess4jClient;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    /**
     * 自动审核文章内容
     *
     * @param id
     * @return
     */
    @Async
    @Override
    @GlobalTransactional
    public void autoScanWmNews(Integer id) throws Exception {
        // 参数校验
        WmNews wmNews = newsMapper.selectById(id);
        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if (wmNews.getStatus() != null && wmNews.getStatus() == 1) {
            //判断是待审核的news

            Map<String, List<Object>> imagesAndText = handleTextAndImages(wmNews);

            // 自定义的敏感词库
            Boolean sensitiveScanText = handleSensitiveScan(imagesAndText.get("text").toString(), wmNews);
            if (!sensitiveScanText) {
                return;
            }

            Boolean textResult = imageAndTextScan(wmNews, imagesAndText.get("text"), "text");
            if (!textResult) {
                return;
            }


            Boolean imagesResult = imageAndTextScan(wmNews, imagesAndText.get("images"), "images");
            if (!imagesResult) {
                return;
            }

            // 审核通过保存到app端
            ResponseResult responseResult = saveAppArticle(wmNews);

            if (responseResult.getCode() != 200) {
                throw new RuntimeException("WmNewsAutoScanServiceImpl-文章审核，保存app端相关文章数据失败");
            }
            Long articleID = (Long) responseResult.getData();

            //=====================自定义异常=============================
//            int a = 1 / 0;
            //==========================================================

            // 更新文章的审核状态位9
            updateWmNews(wmNews, WmNews.Status.PUBLISHED.getCode(), "审核通过",articleID);

        }
    }

    /**
     * 自管理敏感词审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    @Override
    public Boolean handleSensitiveScan(String content, WmNews wmNews) {
        Boolean flag = Boolean.TRUE;
        List<WmSensitive> wmSensitives = sensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        // 初始化敏感词词库
        SensitiveWordUtil.initMap(sensitiveList);
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size() > 0) {
            updateWmNews(wmNews, (short) 2, "当前文章中存在违规内容");
            flag = Boolean.FALSE;
        }

        return flag;
    }

    /**
     * 同步app端和媒体端的数据（上架 下架）
     *
     * @param id
     */
    @Override
    public void dataSynchronization(Integer id) throws Exception {
        WmNews wmNews = newsMapper.selectById(id);
        if (wmNews!=null){
            ResponseResult result = saveAppArticle(wmNews);
        }
    }

    /**
     * 封装数据并调用article客户端保存数据
     *
     * @param wmNews
     * @return
     */
    private ResponseResult saveAppArticle(WmNews wmNews) throws Exception {
        ArticleDtoBuilder articleDtoBuilder = new ArticleDtoBuilder(wmNews, wmChannelMapper, wmUserMapper);
        ArticleDto articleDto = articleDtoBuilder.buildBeanCopy()
                .buildAuthor()
                .buildBasic()
                .buildChannel()
                .builder();
        return articleClient.saveArticle(articleDto);
    }


    /**
     * 返回需要审核的文本和图片链接
     *
     * @param wmNews
     * @return
     */
    private Map<String, List<Object>> handleTextAndImages(WmNews wmNews) {
        Map<String, List<Object>> map = new HashMap<>();
        // 获取文章内容数组
        List<Map> list = JSON.parseArray(wmNews.getContent(), Map.class);
        // 获取文本内容集合
        List<Object> textList = list.stream().filter(item -> "text".equals(item.get("type"))).map(item -> item.get("value")).collect(Collectors.toList());
        // 防止标题内容违规，所以将标题也添加进审核内容
        textList.add(wmNews.getTitle());
        // 获取内容图片url集合
        List<Object> contentImages = list.stream().filter(item -> "image".equals(item.get("type"))).map(item -> item.get("value")).collect(Collectors.toList());
        // 获取封面图片然后将所有图片组装在一起
        String newsCoverImages = wmNews.getImages();
        String images = StringUtils.join(contentImages, ",");
        if (newsCoverImages != null && !"".equals(newsCoverImages)) {

            images = newsCoverImages + "," + images;
        }
        String[] split = images.split(",");
        List<Object> imagesUrl = new ArrayList<>();
        Collections.addAll(imagesUrl, split);
        // 对图片url去重
        imagesUrl = imagesUrl.stream().distinct().collect(Collectors.toList());

        map.put("text", textList);
        map.put("images", imagesUrl);
        return map;

    }


    /**
     * 审核内容
     *
     * @param wmNews
     * @param textsOrImages
     * @param type
     */
    private Boolean imageAndTextScan(WmNews wmNews, List<Object> textsOrImages, String type) throws Exception {
        if (textsOrImages.size() == 0) {
            return true;
        }
        String suggestion = "";

        if ("text".equals(type)) {
            //获取文本内容
            StringBuilder content = new StringBuilder();
            for (Object text : textsOrImages) {
                content.append(text);
            }
            suggestion = greenTextScan.greeTextScan(content.toString()).get("suggestion").toString();
        }
        if ("images".equals(type)) {
            // 获取图片内容
            List<byte[]> byteList = new ArrayList<>();
            byte[] bytes;
            for (Object url : textsOrImages) {
                if (url != null) {
                     bytes = fileStorageService.downLoadFile(url.toString());
                    //从byte[]转换为butteredImage
                    ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                    BufferedImage imageFile = ImageIO.read(in);
                    String result = tess4jClient.doOCR(imageFile);

                    Boolean sensitiveScanImage = handleSensitiveScan(result, wmNews);
                    if (!sensitiveScanImage) {
                        return Boolean.FALSE;
                    }
                    byteList.add(bytes);
                }
            }
            suggestion = greenImageScan.imageScan(byteList).get("suggestion").toString();
        }
        if ("block".equals(suggestion)) {
            updateWmNews(wmNews, (short) 2, "当前文章中存在违规内容");
            return false;
        }
        if ("review".equals(suggestion)) {
            updateWmNews(wmNews, (short) 3, "当前文章中存在不确定内容");
            return false;
        }

        return true;

    }

    /**
     * 修改wmNews状态并且设置拒绝理由
     *
     * @param wmNews
     * @param status
     * @param reason
     */

    private void updateWmNews(WmNews wmNews, short status, String reason ) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        newsMapper.updateById(wmNews);
    }
    private void updateWmNews(WmNews wmNews, short status, String reason,Long articleId ) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNews.setArticleId(articleId);
        newsMapper.updateById(wmNews);
    }
}

